package Client;




import java.io.Serializable;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;

import common.ClientInterface;
import common.Ranking;
import common.RmiInterface;
import common.ServerInterface;
import common.TurnInterface;
import common.UserMap;
import common.exception.BusyNameException;
import common.exception.FailedAuthenticationException;
import common.exception.FullMatchException;
import common.exception.GameException;
import common.exception.InvalidIdException;
import common.exception.InvalidTokenException;
import common.exception.NotInMatchException;


/**
 * La classe fornisce il supporto per rmi lato client. 
 * Implementa clientInterface e RmiInterface per la comunicazione Server-Client
 * e serverInterface per la comunicazione Client-server
 * 
 * @author Jacopo Ferrigno
 *
 */

public class RmiServer extends UnicastRemoteObject implements ClientInterface, ServerInterface, RmiInterface, TurnInterface,Serializable{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	//Parametri di connessione
	private String host="localhost";
	private String ServerName="RmiServer";
	private String Game="Game";
	private String myUserName;
	//Oggetto remoto e Registry
	private transient RmiInterface server;
	private transient ServerInterface myGame;
	//Gestione turni
	private  boolean isChanged = false;
	private String playerName=null;
	//gestione chiusura del thread
	boolean close=false;
	
	/**
	 * Il costruttore cerca di recuperare gli oggetti Game e Server dal localhost.
	 * 
	 * @throws MalformedURLException nel caso non riesca a risolve l'indirizzo del sever
	 * @throws RemoteException nel caso sorgano problemi nella comunicazione via RMI
	 * @throws NotBoundException Nel caso non vengano trovati gli ogetti remoti sul server,
	 * presumibilmente significa che il server non e' partito.
	 */
	
	public RmiServer() throws MalformedURLException, RemoteException, NotBoundException{
		
		this("localhost");
	}

	/**
	 * Il costruttore cerca di recuperare gli oggetti Game e Server dal host passato come parametro.
	 * 
	 * @param host 'lindirizzo del server di destinazione
	 * 
	 * @throws MalformedURLException nel caso non riesca a risolve l'indirizzo del sever
	 * @throws RemoteException nel caso sorgano problemi nella comunicazione via RMI
	 * @throws NotBoundException Nel caso non vengano trovati gli ogetti remoti sul server,
	 * presumibilmente significa che il server non e' partito.
	 */
	
	public RmiServer(String host) throws MalformedURLException, RemoteException, NotBoundException{
		this.host=host;
		
		//Ottengo oggetto remoto del server;
		this.myGame=(ServerInterface)Naming.lookup("rmi://"+this.host+"/"+this.Game);
		this.server=(RmiInterface)Naming.lookup("rmi://"+this.host+"/"+this.ServerName);



	}
	/*
	 * (non-Javadoc)
	 * @see common.ClientInterface#notifyTurn(java.lang.String)
	 */
	@Override
	public void notifyTurn(String newUser) throws RemoteException {
		this.isChanged=true;
		this.playerName=newUser;
		
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#inGame(int)
	 */
	@Override
	public void inGame(int token) throws InvalidTokenException,
			FullMatchException, RemoteException {
		this.myGame.inGame(token);
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#newSpecies(int, java.lang.String, char)
	 */
	@Override
	public void newSpecies(int token, String name, char type)
			throws InvalidTokenException, BusyNameException, RemoteException {
		this.myGame.newSpecies(token, name, type);
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#newUser(java.lang.String, java.lang.String)
	 */
	@Override
	public void newUser(String username, String psw) throws BusyNameException,
			RemoteException {
		this.myGame.newUser(username, psw);
		
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#growDino(int, int)
	 */
	@Override
	public void growDino(int token, int idDino) throws InvalidTokenException,
			NotInMatchException, InvalidIdException, GameException,
			RemoteException {
		this.myGame.growDino(token, idDino);
		
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#egg(int, int)
	 */
	@Override
	public int egg(int token, int idDIno) throws InvalidTokenException,
			NotInMatchException, InvalidIdException, GameException,
			RemoteException {
		return this.myGame.egg(token, idDIno);
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getRanking(int)
	 */
	@Override
	public Ranking getRanking(int token) throws InvalidTokenException,
			RemoteException {
		return this.myGame.getRanking(token);
		
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getPlayers(int)
	 */
	@Override
	public String[] getPlayers(int token) throws InvalidTokenException,
			RemoteException {
		
		return this.myGame.getPlayers(token);
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getDinoList(int)
	 */
	@Override
	
	public Integer[] getDinoList(int token) throws InvalidTokenException,
			NotInMatchException, RemoteException {
		Integer [] dinolist=this.myGame.getDinoList(token);
		
		return dinolist;
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getMap(int)
	 */
	@Override
	public UserMap getMap(int token) throws InvalidTokenException,
			NotInMatchException, RemoteException {
		
		return this.myGame.getMap(token);
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getDinoStat(int, int)
	 */
	@Override
	public Vector getDinoStat(int token, int idDino)
			throws InvalidTokenException, InvalidIdException,
			NotInMatchException, RemoteException {
		
		return this.myGame.getDinoStat(token, idDino);
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getDinoVisual(int, int)
	 */
	@Override
	public UserMap getDinoVisual(int token, int idDino)
			throws InvalidTokenException, InvalidIdException,
			NotInMatchException, RemoteException {
		
		return this.myGame.getDinoVisual(token, idDino);
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#move(int, int, int[])
	 */
	@Override
	public char move(int token, int idDino, int[] destination)
			throws InvalidTokenException, InvalidIdException,
			NotInMatchException, GameException, RemoteException {
		
		return this.myGame.move(token, idDino, destination);
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#login(java.lang.String, java.lang.String)
	 */
	@Override
	public int login(String username, String psw)
			throws FailedAuthenticationException, RemoteException {
		
		this.myUserName=username;
		int token=this.myGame.login(username, psw);
		//Mi aggiungo sul server per callback
		
		this.server.add(this.myUserName, this,this, token);
		
		return token;
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#logout(int)
	 */
	@Override
	public void logout(int token) throws InvalidTokenException, RemoteException {
		this.server.dell(this.myUserName);
		this.myGame.logout(token);
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#skipTurn(int)
	 */
	@Override
	public void skipTurn(int token) throws InvalidTokenException,
			NotInMatchException, GameException, RemoteException {
		
		this.myGame.skipTurn(token);
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#useTurn(int)
	 */
	@Override
	public void useTurn(int token) throws InvalidTokenException,
			NotInMatchException, GameException, RemoteException {
		
		this.myGame.useTurn(token);
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#outGame(int)
	 */
	@Override
	public void outGame(int token) throws InvalidTokenException,
			RemoteException {
		this.myGame.outGame(token);
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see common.TurnInterface#isChanged()
	 */
	@Override
	public synchronized boolean isChanged(){
		boolean tempIsChanged=this.isChanged;
		this.isChanged=false;
		return tempIsChanged;
		
		
	}

	/*
	 * (non-Javadoc)
	 * @see common.TurnInterface#getPlayer()
	 */
	@Override
	public synchronized String getPlayer(){
		this.isChanged=false;
		return this.playerName; 
		
	}


	/*
	 * (non-Javadoc)
	 * @see common.RmiInterface#dell(java.lang.String)
	 */
	@Override
	public int dell(String host) throws RemoteException {
		
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * @see common.RmiInterface#ping(int)
	 */
	@Override
	public synchronized int ping(int msg) throws RemoteException {
		
		return msg;
	}
	
	/**
	 * Avvia la chiusura dei RmiServer.
	 * 
	 */
	public void close(){
		this.close=true;
		
	}

	/*
	 * (non-Javadoc)
	 * @see common.RmiInterface#add(java.lang.String, common.ClientInterface, common.RmiInterface, int)
	 */
	@Override
	public int add(String host, ClientInterface newClient, RmiInterface newPingClient, int token)
			throws RemoteException {

		return 0;
	}


}
